package com.example.interview.example.mobileBilling;

import java.util.Date;

/**
 * 1.假如用户在2月时订购从3月以后的套餐，那么在结算2月份的费用时，不能使用订购的套餐计费方式，而应该使用原先的套餐计费方式；结算3月以后的费用时，就应采用订购的套餐计费方式了。显然，要处理某项业务功能的月账单费用，在PackStrategy中类中要为之存储两份ComputeStrategy对象，一份是原先或当前的套餐计费策略，另一份是订购的从某个月开始的套餐计费策略。
 * 2.
 * 问： 假设2月份的时候订3月以后的套餐， 2月底计算2月份的费用时用哪个套餐？3月底计算3月份的费用时用哪个套餐？
 * 答： 2月底计算2月份的费用时用PackStrategy中的原先或当前的套餐计费策略， 3月底计算3月份的费用时用订购的套餐计费策略。
 * 总结：当计算某月的账单费用时，是采用PackStrategy中的原先或当前的套餐计费策略，还是采用订购的从某个月开始的套餐计费策略呢？这就要看是在计算哪个月的账单费用了，如果“计算账单费用的当前年月份”大于或等于“订购的从某个月开始的套餐计费策略的起效年月份”，那么就要用订购的从某个月开始的套餐计费策略，否则，就采用PackStrategy中的原先或当前的套餐计费策略。
 * 3.
 * 问： 2月的初始计费策略为套餐0， 2月份的时候订3月以后的套餐1，3月份的时候又订4月以后的套餐2，请问，3月底计算3月份的费用时用哪个套餐？
 * 答： 3月底计算3月份的费用时应该用套餐1。在程序代码中，在3月订4月的套餐2时，如果直接对订购变量进行赋值，它将冲掉 2月份订购的3月份以后的套餐1信息，而PackStrategy中的原先或当前的计费策略为套餐0，这样在3月底计算3月份的费用时，将得到错误的结果。所以，应该先将2月份订购的3月份以后的套餐1赋值给PackStrategy中的用于记录原先或当前的套餐计费策略的变量，再用3月订4月的套餐2对订购变量赋值，这样在3月底计算3月份的费用时，采用PackStrategy中的原先或当前的套餐计费策略，正好就是2月份订购的3月份以后的套餐1。
 * 4.
 * 问： 2月的初始计费策略为套餐0， 2月份的时候订了3月以后的套餐1，随后，还是在2月份的时候又重新订购3月以后的套餐，改订为套餐2，请问，2月底计算2月份的费用时用哪个套餐？
 * 答：还应该用2月的初始计费策略套餐0。也就是说，在2月份的时候又重新订购3月以后的套餐2时，应该直接对订购变量进行赋值，让它冲掉 2月份订购的3月份以后的套餐1信息，而不要将2月份订购的3月份以后的套餐1赋值给PackStrategy中的用于记录原先或当前的套餐计费策略的变量，这一点与上面的情况正好不同。
 * 总结：当重新订购新的套餐时，只有原来订购的套餐对当前的年月份起作用时（也就是 “订购变量中存储的日期”小于或等于当前的年月份，即“新订购的套餐的年月份”大于“订购变量中存储的日期”，因为订购的年月份总是当前月份基础上加1），原来订购的套餐信息才要赋值给PackStrategy中的用于记录原先或当前的套餐计费策略的变量，以便计算当前月的费用时使用，否则，如果原来订购的套餐对当前的年月份是不起作用，那么，则不能将原来订购的套餐信息才要赋值给PackStrategy中的用于记录原先或当前的套餐计费策略的变量， 让它直接被新订购的策略冲掉即可。
 * 5.根据面向对象的封装特性，当我们订购新的计费策略时，原来订购的计费策略是否对当前月有效，即是否将原来订购的套餐信息赋值给PackStrategy中的用于记录原先或当前的套餐计费策略的变量， 这个功能不是在PackStrategy类中完成，而是在订购记录对象中完成，因为原来订购的套餐策略的订购日期是存储在订购记录类中的。同样的道理，在计算某月的账单费用时，是否采用订购的从某个月开始的套餐计费策略，这一功能也是由订购记录类来提供。
 */
public class PackStrategy { //（用于存储用户的各项业务套餐策略）
    private int customerType;
    private int packType = 0;
    private ComputeStrategy currentStrategies[] = new ComputeStrategy[3];
    private Rent rent;
    private OrderedStrategyHolder<ComputeStrategy> orderedStrategies[] = new OrderedStrategyHolder[]{
            new OrderedStrategyHolder<ComputeStrategy>(),
            new OrderedStrategyHolder<ComputeStrategy>(),
            new OrderedStrategyHolder<ComputeStrategy>(),
    };
    private OrderedStrategyHolder<Rent> orderedRent = new OrderedStrategyHolder<Rent>();

    public PackStrategy(int customerType, int packType, Rent rent) {
        this.customerType = customerType;
        this.packType = packType;
        this.rent = rent;
        for (int i = 0; i < 3; i++) {
            currentStrategies[i] = new ComputeStrategy(customerType, packType, i);
        }

    }

    public Rent getValidRent(Date month) {
        Rent validRent = orderedRent.getValidComputeStrategy(month);
        return validRent == null ? rent : validRent;

    }

    public void orderRent(Date orderedMonth, Rent rent) {
        Rent oldRent = orderedRent.order(orderedMonth, rent);
        if (oldRent != null) {
            this.rent = oldRent;
        }
    }

    public void cancelRent(Date orderedMonth, Rent rent) {
        orderRent(orderedMonth, null);
    }

    public ComputeStrategy getValidPhonePack(Date month) {
        ComputeStrategy computeStrategy = (ComputeStrategy) orderedStrategies[0].getValidComputeStrategy(month);
        return computeStrategy == null ? currentStrategies[0] : computeStrategy;
    }

    public ComputeStrategy getValidMessagePack(Date month) {
        ComputeStrategy computeStrategy = (ComputeStrategy) orderedStrategies[1].getValidComputeStrategy(month);
        return computeStrategy == null ? currentStrategies[1] : computeStrategy;
    }

    public ComputeStrategy getValidDataPack(Date month) {
        ComputeStrategy computeStrategy = (ComputeStrategy) orderedStrategies[2].getValidComputeStrategy(month);
        return computeStrategy == null ? currentStrategies[2] : computeStrategy;
    }

    public void orderPhonePack(Date orderedMonth, int packType) {
        ComputeStrategy oldComputeStrategy = orderedStrategies[0].order(orderedMonth, new ComputeStrategy(customerType, packType, 0));
        if (oldComputeStrategy != null) {
            this.currentStrategies[0] = oldComputeStrategy;
        }

    }

    public void orderMessagePack(Date orderedMonth, int packType) {
        ComputeStrategy oldComputeStrategy = orderedStrategies[1].order(orderedMonth, new ComputeStrategy(customerType, packType, 1));
        if (oldComputeStrategy != null) {
            this.currentStrategies[1] = oldComputeStrategy;
        }
    }

    public void orderDataPack(Date orderedMonth, int packType) {
        ComputeStrategy oldComputeStrategy = orderedStrategies[2].order(orderedMonth, new ComputeStrategy(customerType, packType, 2));
        if (oldComputeStrategy != null) {
            this.currentStrategies[2] = oldComputeStrategy;
        }
    }

    public void cancelPhonePack(Date orderedMonth) {
        orderPhonePack(orderedMonth, 0);
    }

    public void cancelMessagePack(Date orderedMonth) {
        orderMessagePack(orderedMonth, 0);
    }

    public void cancelDataPack(Date orderedMonth) {
        orderDataPack(orderedMonth, 0);
    }

/*	public PhoneComputeStrategy getOrderedPhonePack(){
		PhoneComputeStrategy phoneHolderStrategy = (PhoneComputeStrategy)phoneOrderedStrategyHolder.getOrderedStrategy();
		return phoneHolderStrategy;
	}

	public MessageComputeStrategy getOrderedMessagePack(){
		MessageComputeStrategy messageHolderStrategy = (MessageComputeStrategy)messageOrderedStrategyHolder.getOrderedStrategy();
		return messageHolderStrategy;
	}

	public DataComputeStrategy getOrderedDataPack(){
		DataComputeStrategy dataHolderStrategy = (DataComputeStrategy)dataOrderedStrategyHolder.getOrderedStrategy();
		return dataHolderStrategy;
	}	*/
}
